using MultiAgentsClient.ChatDataStructures;
using MultiAgentsClient.Manager.DataModel;
using MultiAgentsClient.Service.SignalRService;
using MultiAgentsClient.Service.WorkflowEngine;
using MultiAgentsClient.Service.WorkflowEngine.BuiltInNodes;
using MultiAgentsShared;
using TextCopy;

using ApiRequest = MultiAgentsClient.Service.SignalRService.SignalRWorkflowService.ApiRequestType;

namespace MultiAgentsClient.Manager;

public class WorkflowManager : ManagerBase
{
    private readonly SignalRWorkflowService signalRWorkflowService;

    private readonly WorkflowDataModel workflowDataModel;
    private readonly UserDataModel userDataModel;
    private readonly SystemConfigDataModel systemConfigDataModel;

    #region events
    // recieve command from UI
    public record CreateNewWorkflowCommand();
    public record RemoveWorkflowCommand(int WorkflowId);
    public record GetAllWorkflowCommand(int? UserId);
    public record GetWorkflowCommand(string WorkflowJson);
    public record ShareWorkflowCommand(int WorkflowId);
    public record UpdateWorkflowCommand(int WorkflowId, string Name, string WorkflowJson);
    public record UpdateWorkflowSubscriptionCommand(BehaviorTreeConfig WorkflowConfig, int UserId);

    // recieve command from signalR
    public record CreateNewWorkflowResponseCommand(int WorkflowId, int UserId, string WorkflowName, string WorkflowJson);
    public record RemoveWorkflowResponseCommand(int WorkflowId);
    public record GetAllWorkflowResponseCommand(List<Workflow> Workflows);
    public record UpdateWorkflowResponseCommand(int WorkflowId, int UserId, string WorkflowName, string WorkflowJson);
    
    // send command to UI
    public record CreateNewWorkflowCompleteCommand(WorkflowDisp WorkflowConfigDisp);
    public record RemoveWorkflowCompleteCommand(int Workflow);
    public record GetAllWorkflowCompleteCommand(List<WorkflowDisp> WorkflowDisps);
    public record UpdateWorkflowCompleteCommand(WorkflowDisp WorkflowConfigDisp);
    #endregion

    public WorkflowManager(
        SystemConfigDataModel systemConfigDataModel,
        SignalRWorkflowService signalRWorkflowService,
        WorkflowDataModel workflowDataModel,
        UserDataModel userDataModel)
    {
        this.signalRWorkflowService = signalRWorkflowService;
        this.workflowDataModel = workflowDataModel;
        this.userDataModel = userDataModel;
        this.systemConfigDataModel = systemConfigDataModel;

        eventBus.Subscribe<CreateNewWorkflowCommand>(CreateNewWorkflowCommandHandler);
        eventBus.Subscribe<RemoveWorkflowCommand>(RemoveWorkflowCommandHandler);
        eventBus.Subscribe<GetAllWorkflowCommand>(GetAllWorkflowCommandHandler);
        eventBus.Subscribe<GetWorkflowCommand>(GetWorkflowCommandHandler);
        eventBus.Subscribe<ShareWorkflowCommand>(ShareWorkflowCommandHandler);
        eventBus.Subscribe<UpdateWorkflowCommand>(UpdateWorkflowCommandHandler);
        eventBus.Subscribe<UpdateWorkflowSubscriptionCommand>(UpdateWorkflowSubscriptionCommandHandler);

        eventBus.Subscribe<CreateNewWorkflowResponseCommand>(CreateNewWorkflowResponseCommandHandler);
        eventBus.Subscribe<UpdateWorkflowResponseCommand>(UpdateWorkflowResponseCommandHandler);
        eventBus.Subscribe<RemoveWorkflowResponseCommand>(RemoveWorkflowResponseCommandHandler);
        eventBus.Subscribe<GetAllWorkflowResponseCommand>(GetAllWorkflowResponseCommandHandler);
    }

    #region request
    private async void CreateNewWorkflowCommandHandler(CreateNewWorkflowCommand _)
    {
        // sample config
        BehaviorTreeConfig newConfig = new(0, userDataModel.Id, "New Workflow");

        string newConfigJson = BehaviorTreeConfig.EmptyTemplate();

        await signalRWorkflowService.SendSignalRRequest(ApiRequest.CreateNewWorkflowRequest.ToString(), new Dictionary<string, object>()
            {
                { "sessionId", systemConfigDataModel.sessionId },
                { "userId", userDataModel.Id },
                { "workflowIdName", newConfig.name },
                { "workflowJson", newConfigJson },
            });
    }

    private async void RemoveWorkflowCommandHandler(RemoveWorkflowCommand cmd)
    {
        await signalRWorkflowService.SendSignalRRequest(ApiRequest.RemoveWorkflowRequest.ToString(), new Dictionary<string, object>()
            {
                { "sessionId", systemConfigDataModel.sessionId },
                { "userId", userDataModel.Id },
                { "workflowId", cmd.WorkflowId },
            });
    }

    public async void GetAllWorkflowCommandHandler(GetAllWorkflowCommand cmd)
    {
        await signalRWorkflowService.SendSignalRRequest(ApiRequest.GetAllWorkflowsByUserRequest.ToString(), new Dictionary<string, object>()
        {
            { "sessionId", systemConfigDataModel.sessionId },
            { "userId", cmd.UserId == null ? userDataModel.Id : (int)cmd.UserId },
        });
    }

    private async void GetWorkflowCommandHandler(GetWorkflowCommand cmd)
    {
        await signalRWorkflowService.SendSignalRRequest(ApiRequest.LoadWorkflowByShareCodeRequest.ToString(), new Dictionary<string, object>()
            {
                { "sessionId", systemConfigDataModel.sessionId },
                { "userId", userDataModel.Id },
                { "workflowJson", cmd.WorkflowJson },
            });
    }

    private void ShareWorkflowCommandHandler(ShareWorkflowCommand cmd)
    {
        BehaviorTreeConfig? workflow = workflowDataModel[cmd.WorkflowId];
        if (workflow == null)
        {
            return;
        }
        ClipboardService.SetText(workflow.configJson);
    }

    public async void UpdateWorkflowCommandHandler(UpdateWorkflowCommand cmd)
    {
        await signalRWorkflowService.SendSignalRRequest(ApiRequest.UpdateWorkflowRequest.ToString(), new Dictionary<string, object>()
            {
                { "sessionId", systemConfigDataModel.sessionId },
                { "userId", userDataModel.Id },
                { "workflowId", cmd.WorkflowId },
                { "workflowIdName", cmd.Name },
                { "workflowJson", cmd.WorkflowJson },
            });
    }

    public async void UpdateWorkflowSubscriptionCommandHandler(UpdateWorkflowSubscriptionCommand cmd)
    {
        BehaviorTreeConfig workflowConfig = cmd.WorkflowConfig;

        if (workflowConfig.TriggerNode is GitlabNode gitlabNode)
        {
            await signalRWorkflowService.SendSignalRRequest(ApiRequest.SubscriptonUserRequest.ToString(), new Dictionary<string, object>()
                {
                    { "sessionId", systemConfigDataModel.sessionId },
                    { "userId", cmd.UserId },
                    { "workflowId", workflowDataModel.selectWorkflow },
                    { "repositoryURL", gitlabNode.RepositoryURL },
                    { "shouldAskMe", gitlabNode.ShouldAskMe },
                });
        }
    }
    #endregion


    #region response
    private void CreateNewWorkflowResponseCommandHandler(CreateNewWorkflowResponseCommand cmd)
    {
        workflowDataModel.AddOrUpdateCahce(cmd.WorkflowId, cmd.UserId, cmd.WorkflowName, cmd.WorkflowJson);
        workflowDataModel.selectWorkflow = cmd.WorkflowId;

        WorkflowDisp? workflowDisp = workflowDataModel?[cmd.WorkflowId]?.ToDisp();
        if (workflowDisp == null)
        {
            return;
        }
        eventBus.Publish(new CreateNewWorkflowCompleteCommand(workflowDisp));
    }

    private void UpdateWorkflowResponseCommandHandler(UpdateWorkflowResponseCommand cmd)
    {
        workflowDataModel.AddOrUpdateCahce(cmd.WorkflowId, cmd.UserId, cmd.WorkflowName, cmd.WorkflowJson);
        workflowDataModel.selectWorkflow = cmd.WorkflowId;

        WorkflowDisp? workflowDisp = workflowDataModel?[cmd.WorkflowId]?.ToDisp();
        if (workflowDisp == null)
        {
            return;
        }
        eventBus.Publish(new UpdateWorkflowCompleteCommand(workflowDisp));
    }

    private void RemoveWorkflowResponseCommandHandler(RemoveWorkflowResponseCommand cmd)
    {
        workflowDataModel.RemoveWorkflowIfExist(cmd.WorkflowId);
        eventBus.Publish(new RemoveWorkflowCompleteCommand(cmd.WorkflowId));
    }

    private void GetAllWorkflowResponseCommandHandler(GetAllWorkflowResponseCommand cmd)
    {
        workflowDataModel.UpdateAllJsonFromDb(cmd.Workflows);
        eventBus.Publish(new GetAllWorkflowCompleteCommand(workflowDataModel.GetAllWorkflowDisps()));
    }
    #endregion
}
